package hotactivity

import (
	"time"

	"advertoper/db"

	"doubimeizhi.com/datatable"
	"doubimeizhi.com/utility"

	"github.com/astaxie/beego"
	log "github.com/cihub/seelog"
)

//获取热门活动页面
func (p *HotActivityInfoService) GetHotActivityInfo(start, length int) []*HotActivityInfo {
	res := make([]*HotActivityInfo, 0, length)

	if aids, ok := activityCatalog[HOTACTIVITY_STATUS_PUBLISH]; ok {
		p.getShowHotActivityInfo(&res, length, HOTACTIVITY_STATUS_PUBLISH, aids)
	}
	rest := length - len(res)
	if rest > 0 {
		if aids, ok := activityCatalog[HOTACTIVITY_STATUS_EXPIRED]; ok {
			p.getShowHotActivityInfo(&res, rest, HOTACTIVITY_STATUS_EXPIRED, aids)
		}
	}
	return res
}

func (p *HotActivityInfoService) getShowHotActivityInfo(res *[]*HotActivityInfo, length, status int, aids []int64) {
	i := 0
	for _, aid := range aids {
		if i >= length {
			break
		}

		if info, ok := hotActivity[aid]; ok {
			*res = append(*res, info)
			i++
		}
	}
}

func (p *HotActivityInfoService) CreateHotActivityInfo(req *HotActivityInfo) bool {
	currentTick := time.Now().Unix()
	status := req.GetStatus()

	/*if HOTACTIVITY_STATUS_EXPIRED == status {
		log.Warnf("cannot create hotactivityinfo for EXPIRED!")
		return false
	}*/

	data := make(map[string]*utility.MySQLFieldValue)
	data["thumbnail_url"] = utility.NewMySQLFieldValue(req.ThumbnailURL, false)
	data["target_url"] = utility.NewMySQLFieldValue(req.TargetURL, false)
	data["pic_size"] = utility.NewMySQLFieldValue(req.Size, false)
	data["title"] = utility.NewMySQLFieldValue(req.Title, false)
	data["create_tick"] = utility.NewMySQLFieldValue(currentTick, false)
	data["publish_tick"] = utility.NewMySQLFieldValue(req.PublishTick, false)
	data["end_tick"] = utility.NewMySQLFieldValue(req.EndTick, false)
	data["update_tick"] = utility.NewMySQLFieldValue(currentTick, false)
	mysqlHelper := db.GetMysqlHelper()
	if _, err := mysqlHelper.SaveRecord(data, "hot_activity"); err != nil {
		log.Errorf("SaveHotActivityInfo error: %s", err.Error())
		return false
	}

	req.Status = status
	return p.addNewActivity(req, status)
}

func (p *HotActivityInfoService) addNewActivity(req *HotActivityInfo, status int) bool {
	dtq := datatable.NewDataTableQuery()
	dtq.SetTableName("hot_activity")
	dtq.PushField(&datatable.FiledItem{Alias: "aid", Field: "max(activity_id)"})
	sql, values := dtq.GenerateSQL()
	mysqlHelper := db.GetMysqlHelper()
	results, err := mysqlHelper.Query(sql, values...)
	if err != nil {
		log.Warnf("sql err: %s, sql: %s, values: %v", err.Error(), sql, values)
		return false
	}
	var aid int64
	if len(results) > 0 {
		aid = mysqlHelper.GetColInt64(results[0], "aid")
	} else {
		log.Warnf("max(activity_id) not found!")
		return false
	}

	req.ActivityId = aid
	hotActivity[aid] = req

	if _, ok := activityCatalog[status]; ok {
		length := len(activityCatalog[status])
		old := activityCatalog[status][:length]
		activityCatalog[status] = make([]int64, 0, length+1)
		activityCatalog[status] = append(activityCatalog[status], aid)
		activityCatalog[status] = append(activityCatalog[status], old...)
	} else {
		activityCatalog[status] = make([]int64, 0)
		activityCatalog[status] = append(activityCatalog[status], aid)
	}
	return true
}

func (p *HotActivityInfoService) ModifyHotActivityInfo(req *HotActivityInfo) bool {
	currentTick := time.Now().Unix()
	status := req.GetStatus()

	data := make(map[string]*utility.MySQLFieldValue)
	data["activity_id"] = utility.NewMySQLFieldValue(req.ActivityId, false)
	if req.ThumbnailURL != "" {
		data["thumbnail_url"] = utility.NewMySQLFieldValue(req.ThumbnailURL, true)
	}
	if req.Size != "" {
		data["pic_size"] = utility.NewMySQLFieldValue(req.Size, true)
	}
	if req.TargetURL != "" {
		data["target_url"] = utility.NewMySQLFieldValue(req.TargetURL, true)
	}
	if req.Title != "" {
		data["title"] = utility.NewMySQLFieldValue(req.Title, true)
	}
	if req.PublishTick != 0 {
		data["publish_tick"] = utility.NewMySQLFieldValue(req.PublishTick, true)
	}
	if req.EndTick != 0 {
		data["end_tick"] = utility.NewMySQLFieldValue(req.EndTick, true)
	}

	data["update_tick"] = utility.NewMySQLFieldValue(currentTick, true)

	mysqlHelper := db.GetMysqlHelper()
	if _, err := mysqlHelper.SaveRecord(data, "hot_activity"); err != nil {
		log.Errorf("ModifyHotActivityInfo error: %s, activity_id: %d", err.Error(), req.ActivityId)
		return false
	}

	return p.modifyHotActivity(req, status)
}

func (p *HotActivityInfoService) modifyHotActivity(req *HotActivityInfo, status int) bool {
	hot := hotActivity[req.ActivityId]
	if hot.Status != status {
		changeCatalog(req.ActivityId, status)
	}

	if req.ThumbnailURL != "" {
		hot.ThumbnailURL = req.ThumbnailURL
	}
	if req.Size != "" {
		hot.Size = req.Size
	}
	if req.TargetURL != "" {
		hot.TargetURL = req.TargetURL
	}
	if req.PublishTick != 0 {
		hot.PublishTick = req.PublishTick
	}
	if req.EndTick != 0 {
		hot.EndTick = req.EndTick
	}
	if req.Title != "" {
		hot.Title = req.Title
	}
	hotActivity[req.ActivityId] = hot
	return true
}

func (p *HotActivityInfoService) DeleteHotActivityInfo(aid int64) bool {
	status := HOTACTIVITY_STATUS_DELETE

	dtd := datatable.NewDataTableDelete()
	dtd.SetTableName("hot_activity")
	dtd.PushCondition("activity_id = ?", aid)
	sql, values := dtd.GenerateSQL()
	mysqlHelper := db.GetMysqlHelper()
	if _, err := mysqlHelper.Exec(sql, values...); err != nil {
		log.Debugf("DeleteHotActivityInfo err, sql:%s, sql, err:%s, activity_id:%d", sql, err.Error(), aid)
		return false
	}

	return p.deleteHotActivity(status, aid)
}

func (p *HotActivityInfoService) deleteHotActivity(status int, aid int64) bool {
	ret := changeCatalog(aid, status)
	delete(hotActivity, aid)
	return ret
}

func (p *HotActivityInfoService) ListHotActivity(start, length int) ([]*HotActivityInfo, int) {
	res := make([]*HotActivityInfo, 0, length)
	lenPublish := getActivityCatalogSize(HOTACTIVITY_STATUS_PUBLISH)
	lenPrePublish := getActivityCatalogSize(HOTACTIVITY_STATUS_PREPUBLISH)
	lenExpired := getActivityCatalogSize(HOTACTIVITY_STATUS_EXPIRED)
	total := lenPublish + lenPrePublish + lenExpired

	if lenPublish > 0 && start < lenPublish {
		eidx := lenPublish
		if start+length < lenPublish {
			eidx = start + length
		}
		p.getShowHotActivityInfo(&res, length, HOTACTIVITY_STATUS_PUBLISH, activityCatalog[HOTACTIVITY_STATUS_PUBLISH][start:eidx])
	}

	rest := length - len(res)
	if lenPrePublish > 0 && rest > 0 {
		sidx := 0
		if start >= lenPublish && start < lenPublish+lenPrePublish {
			sidx = start - lenPublish
		}
		if sidx < lenPrePublish {
			eidx := lenPrePublish
			if sidx+rest < lenPrePublish {
				eidx = sidx + rest
			}
			p.getShowHotActivityInfo(&res, rest, HOTACTIVITY_STATUS_PREPUBLISH, activityCatalog[HOTACTIVITY_STATUS_PREPUBLISH][sidx:eidx])
		}
	}

	rest = length - len(res)
	if lenExpired > 0 && rest > 0 {
		sidx := 0
		if start >= lenPublish+lenPrePublish && start < lenPublish+lenPrePublish+lenExpired {
			sidx = start - lenPublish - lenPrePublish
		}
		if sidx < lenExpired {
			eidx := lenExpired
			if sidx+rest < lenExpired {
				eidx = sidx + rest
			}
			p.getShowHotActivityInfo(&res, rest, HOTACTIVITY_STATUS_EXPIRED, activityCatalog[HOTACTIVITY_STATUS_EXPIRED][sidx:eidx])
		}
	}
	return res, total
}

func changeCatalog(activityId int64, status int) bool { //change activity catalog or delete
	oldStatus := hotActivity[activityId].Status
	if oldStatus == status {
		return true
	}

	for index, aid := range activityCatalog[oldStatus] {
		if aid == activityId {
			activityCatalog[oldStatus] = append(activityCatalog[oldStatus][:index], activityCatalog[oldStatus][index+1:]...)
			break
		}
	}

	if status != HOTACTIVITY_STATUS_DELETE {
		if _, ok := activityCatalog[status]; ok {
			aidSlice := make([]int64, 0, 1)
			aidSlice = append(aidSlice, activityId)
			activityCatalog[status] = append(aidSlice, activityCatalog[status]...)
		} else {
			activityCatalog[status] = make([]int64, 0)
			activityCatalog[status] = append(activityCatalog[status], activityId)
		}
		hotActivity[activityId].Status = status
	}
	return true
}

func checkHotActivityStatus() {
	//log.Debugf("entering ......")
	catalogs := []int{HOTACTIVITY_STATUS_PUBLISH, HOTACTIVITY_STATUS_PREPUBLISH}
	changedItems := make(map[int64]int)
	for _, catalog := range catalogs {
		if aids, ok := activityCatalog[catalog]; ok {
			for _, aid := range aids {
				status := hotActivity[aid].GetStatus()
				//log.Debugf("check aid: %d, catalog: %d, status: %d", aid, catalog, status)
				if status == catalog {
					continue
				}
				changedItems[aid] = status
			}
		}
	}
	for aid, status := range changedItems {
		log.Debugf("checkHotActivityStatus aid: %d, status: %d", aid, status)
		changeCatalog(aid, status)
	}
}

func periodupMemory() {
	reloadInterval := beego.AppConfig.DefaultInt("checkHotActivityStatus", 60)
	interval := time.Second * time.Duration(reloadInterval)
	t1 := time.NewTimer(interval)
	for {
		select {
		case <-t1.C:
			checkHotActivityStatus()
			t1.Reset(interval)
		}
	}
}
